// -------------------------------------------------
// BlinKit - BlinKit Library
// -------------------------------------------------
//   File Name: qjs.cpp
// Description: QuickJS Helpers
//      Author: Ziming Li
//     Created: 2022-03-04
// -------------------------------------------------
// Copyright (C) 2022 MingYang Software Technology.
// -------------------------------------------------

#include "./qjs.h"

namespace BlinKit {
namespace qjs {

static JSValue WrapWTFCString(JSContext *ctx, const CString &s)
{
    return JS_NewStringLen(ctx, s.data(), s.length());
}

JSValue WrapString(JSContext *ctx, const AtomicString &s)
{
    if (s.isNull())
        return JS_NULL;
    return WrapWTFCString(ctx, s.utf8());
}

JSValue WrapString(JSContext *ctx, const String &s)
{
    if (s.isNull())
        return JS_NULL;
    return WrapWTFCString(ctx, s.utf8());
}

AtomicString ToAtomicString(JSContext *ctx, JSValue v)
{
    AtomicString ret;

    size_t l = 0;
    const char *ps = JS_ToCStringLen(ctx, &l, v);
    ret = AtomicString::fromUTF8(ps, l);
    JS_FreeCString(ctx, ps);

    return ret;
}

std::string ToStdString(JSContext *ctx, JSValue v)
{
    std::string ret;

    size_t l = 0;
    const char *ps = JS_ToCStringLen(ctx, &l, v);
    ret.assign(ps, l);
    JS_FreeCString(ctx, ps);

    return ret;
}

std::string ToStdString(JSContext *ctx, JSAtom atom)
{
    std::string ret;

    const char *psz = JS_AtomToCString(ctx, atom);
    ret.assign(psz);
    JS_FreeCString(ctx, psz);

    return ret;
}

String ToWTFString(JSContext *ctx, JSValue v)
{
    String ret;

    size_t l = 0;
    const char *ps = JS_ToCStringLen(ctx, &l, v);
    ret = String::fromUTF8(ps, l);
    JS_FreeCString(ctx, ps);

    return ret;
}

void DumpException(JSContext *ctx)
{
    JSValue e = JS_GetException(ctx);
    ASSERT(JS_IsObject(e));

    std::string s;

    JSValue v = JS_GetPropertyStr(ctx, e, "message");
    s.append("JS EXCEPTION: ").append(ToStdString(ctx, v)).push_back('\n');
    JS_FreeValue(ctx, v);

    v = JS_GetPropertyStr(ctx, e, "stack");
    s.append(ToStdString(ctx, v));
    JS_FreeValue(ctx, v);

    JS_FreeValue(ctx, e);
    zed::log("{}", s);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Context::Context(JSContext &ctx) : m_ctx(&ctx)
{
}

JSValue Context::ReturnException(void)
{
    ASSERT(hadException());
    ASSERT(false); // BKTODO:
    return JS_EXCEPTION;
}

bool Context::ToString(std::string &dst, JSValue v)
{
    bool ret = false;

    if (JS_IsString(v))
    {
        dst = ToStdString(m_ctx, v);
        return true;
    }

    JSValue s = JS_ToString(m_ctx, v);
    if (JS_IsString(s))
    {
        dst = ToStdString(m_ctx, s);
        ret = true;
    }
    JS_FreeValue(m_ctx, s);

    return ret;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace Crawler {

JSValue DummyFunction(JSContext *ctx, JSValueConst, int argc, JSValueConst *argv)
{
    return JS_UNDEFINED;
}

}

} // namespace qjs
} // namespace BlinKit
